﻿/// <reference path="_namespace.js" />
/// <reference path="/ajax/math/Vector3.js"/>
/// <reference path="BoundingFrustum.js"/>
/// <reference path="BoundingSphere.js"/>
/// <reference path="PlaneIntersectionType.js"/>
/// <reference path="/ajax/math/Plane3.js"/>
/// <reference path="/ajax/math/Ray3.js"/>
/// <reference path="/ajax/types/Float.js"/>
/// <reference path="ContainmentType.js"/>

/*****************************************************************************
Ajaxna library class definition. Inheriting from ajax.BaseObject.
Author: krobinson 11/5/2008 1:38:19 AM.
Class:  ajax.xna.framework.BoundingBox
*****************************************************************************/

$addNamespace("ajax.xna.framework");
$imports("ajax.math.Vector3");
$imports("ajax.xna.framework.PlaneIntersectionType");
$imports("ajax.types.Float");
$imports("ajax.xna.framework.ContainmentType");

//-----------------------------------------------------------------------------

ajax.xna.framework.BoundingBox = function(vecMin, vecMax)
{///<summary>Creates an instance of BoundingBox.</summary>
    ///<param name="vecMin" type="ajax.math.Vector3">The minimum point the BoundingBox includes.</param>
    ///<param name="vecMax" type="ajax.math.Vector3">The maximum point the BoundingBox includes.</param>    
    this.min = vecMin;
    this.max = vecMax;
}
$extend("ajax.xna.framework.BoundingBox", "");
//-----------------------------------------------------------------------------

ajax.xna.framework.BoundingBox.prototype.cornerCount = 8;
ajax.xna.framework.BoundingBox.prototype.min = ajax.math.Vector3.prototype;
ajax.xna.framework.BoundingBox.prototype.max = ajax.math.Vector3.prototype;
ajax.xna.framework.BoundingBox.prototype.getCorners = function()
{///<returns type="Array" arrayElement="ajax.math.Vector3"/>
    var Vector3 = ajax.math.Vector3
    return [
        new Vector3(this.min.x, this.max.y, this.max.z),
        new Vector3(this.max.x, this.max.y, this.max.z),
        new Vector3(this.max.x, this.min.y, this.max.z),
        new Vector3(this.min.x, this.min.y, this.max.z),
        new Vector3(this.min.x, this.max.y, this.min.z),
        new Vector3(this.max.x, this.max.y, this.min.z),
        new Vector3(this.max.x, this.min.y, this.min.z),
        new Vector3(this.min.x, this.min.y, this.min.z)
        ];
}

ajax.xna.framework.BoundingBox.createFromPoints = function(vecPointsArray)
{///<param name="vecPointsArray" type="Array" elementType="ajax.math.Vector3"/>
    var Vector3 = ajax.math.Vector3;
    var vector2 = new Vector3(ajax.types.Float.maxValue);
    var vector1 = new Vector3(ajax.types.Float.minValue);

    var vector3;
    for (var i = 0; i < vecPointsArray.length; i++)
    {
        vector3 = vecPointsArray[i];
        vector2 = Vector3.min(vector2, vector3);
        vector1 = Vector3.max(vector1, vector3);
    }
    return new ajax.xna.framework.BoundingBox(vector2, vector1);
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.createFromSphere = function(sphere)
{///<param name="sphere" type="ajax.xna.framework.BoundingSphere"/>
    var min = new ajax.math.Vector3(
        sphere.center.x - sphere.radius,
        sphere.center.y - sphere.radius,
        sphere.center.z - sphere.radius
    );
    var max = new ajax.math.Vector3(
        sphere.center.x + sphere.radius,
        sphere.center.y + sphere.radius,
        sphere.center.z + sphere.radius
    );
    return new ajax.xna.framework.BoundingBox(min, max);
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.supportMapping = function(v)
{///<param name="v" type="ajax.math.Vector3"/>
    return new ajax.math.Vector3((v.x >= 0) ? this.max.x : this.min.x, (v.y >= 0) ? this.max.y : this.min.y, (v.z >= 0) ? this.max.z : this.min.z);
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.intersectsBoundingBox = function(box)
{///<param name="box" type="ajax.xna.framework.BoundingBox"/>    
    if ((this.max.x < box.min.x) || (this.min.x > box.max.x))
        return false;

    if ((this.max.y < box.min.y) || (this.min.y > box.max.y))
        return false;

    return ((this.max.z >= box.min.z) && (this.min.z <= box.max.z));
}

//-----------------------------------------------------------------------------
/* Frustum does not yet implement this.
ajax.xna.framework.BoundingBox.prototype.intersectsBoundingFrustum = function(frustum)
{///<param name="frustum" type="ajax.xna.framework.BoundingFrustum"/>
return frustum.intersectsBoundingBox(this);
}
*/
//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.intersectsBoundingSphere = function(sphere)
{///<param name="sphere" type="ajax.xna.framework.BoundingSphere"/>
    var Vector3 = ajax.math.Vector3;

    var vector = Vector3.clamp(sphere.center, this.min, this.max);
    var num = Vector3.distanceSquared(sphere.center, vector);
    return (num <= (sphere.radius * sphere.radius));
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.intersectsPlane = function(plane)
{///<param name="plane" type="ajax.math.Plane3"/>    
    var Vector3 = ajax.math.Vector3;
    var vector = new Vector3();
    var vector2 = new Vector3();

    vector2.x = (plane.normal.x >= 0) ? this.min.x : this.max.x;
    vector2.y = (plane.normal.y >= 0) ? this.min.y : this.max.y;
    vector2.z = (plane.normal.z >= 0) ? this.min.z : this.max.z;
    vector.x = (plane.normal.x >= 0) ? this.max.x : this.min.x;
    vector.y = (plane.normal.y >= 0) ? this.max.y : this.min.y;
    vector.z = (plane.normal.z >= 0) ? this.max.z : this.min.z;
    var num = ((plane.normal.x * vector2.x) + (plane.normal.y * vector2.y)) + (plane.normal.z * vector2.z);
    if ((num + plane.distance) > 0)
    {
        return ajax.xna.framework.PlaneIntersectionType.Front;
    }
    num = ((plane.normal.x * vector.x) + (plane.normal.y * vector.y)) + (plane.normal.z * vector.z);
    if ((num + plane.distance) < 0)
    {
        return ajax.xna.framework.PlaneIntersectionType.Back;
    }
    return ajax.xna.framework.PlaneIntersectionType.Intersecting;
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.intersectsRay = function(ray)
{///<param name="ray" type="ajax.math.Ray3"/>
    ///<returns type="float" mayBeNull="true"/>
    //ray = ajax.math.Ray3.cast(ray);
    var num = 0;
    var maxValue = ajax.types.Float.maxValue;
    if (Math.abs(ray.normal) < 1E-06)
    {
        if ((ray.origin.x < this.min.x) || (ray.origin.x > this.max.x))
        {
            return null;
        }
    }
    else
    {
        var num11 = 1 / ray.normal.x;
        var num8 = (this.min.x - ray.origin.x) * num11;
        var num7 = (this.max.x - ray.origin.x) * num11;
        if (num8 > num7)
        {
            var num14 = num8;
            num8 = num7;
            num7 = num14;
        }
        num = Math.max(num8, num);
        maxValue = Math.min(num7, maxValue);
        if (num > maxValue)
        {
            return null;
        }
    }
    if (Math.abs(ray.normal.y) < 1E-06)
    {
        if ((ray.origin.y < this.min.y) || (ray.origin.y > this.max.y))
        {
            return null;
        }
    }
    else
    {
        var num10 = 1 / ray.normal.y;
        var num6 = (this.min.y - ray.origin.y) * num10;
        var num5 = (this.max.y - ray.origin.y) * num10;
        if (num6 > num5)
        {
            var num13 = num6;
            num6 = num5;
            num5 = num13;
        }
        num = Math.max(num6, num);
        maxValue = Math.min(num5, maxValue);
        if (num > maxValue)
        {
            return null;
        }
    }
    if (Math.abs(ray.normal.z) < 1E-06)
    {
        if ((ray.origin.z < this.min.z) || (ray.origin.z > this.max.z))
        {
            return null;
        }
    }
    else
    {
        var num9 = 1 / ray.normal.z;
        var num4 = (this.min.z - ray.origin.z) * num9;
        var num3 = (this.max.z - ray.origin.z) * num9;
        if (num4 > num3)
        {
            var num12 = num4;
            num4 = num3;
            num3 = num12;
        }
        num = Math.max(num4, num);
        maxValue = Math.min(num3, maxValue);
        if (num > maxValue)
        {
            return null;
        }
    }
    return num;
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.containsBoundingBox = function(box)
{///<param name="box" type="ajax.xna.framework.BoundingBox"/>
    ///<returns type="ajax.xna.framework.ContainmentType">Tests weather this box contains another box</returns>

    if ((this.max.x < box.min.x) || (this.min.x > box.max.x))
        return ajax.xna.framework.ContainmentType.Disjoint;

    if ((this.max.y < box.min.y) || (this.min.y > box.max.y))
        return ajax.xna.framework.ContainmentType.Disjoint;

    if ((this.max.z < box.min.z) || (this.min.z > box.max.z))
        return ajax.xna.framework.ContainmentType.Disjoint;

    if ((((this.min.x <= box.min.x) && (box.max.x <= this.max.x)) && ((this.min.y <= box.min.y) && (box.max.y <= this.max.y))) && ((this.min.z <= box.min.z) && (box.max.z <= this.max.z)))
        return ajax.xna.framework.ContainmentType.Contains;

    return ajax.xna.framework.ContainmentType.Intersects;
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.containsVector3 = function(point)
{
    point = ajax.math.Vector3.cast(point);
    if ((((this.min.x <= point.x) && (point.x <= this.max.x)) && ((this.min.y <= point.y) && (point.y <= this.max.y))) && ((this.min.z <= point.z) && (point.z <= this.max.z)))
    {
        return ajax.xna.framework.ContainmentType.Contains;
    }
    return ajax.xna.framework.ContainmentType.Disjoint;
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.containsBoundingFrustum = function(frustum)
{///<param name="frustum" type="ajax.xna.framework.BoundingFrustum"/>
    if (!frustum.intersectsBoundingBox(this))
        return ajax.xna.framework.ContainmentType.Disjoint;

    for (var i = 0; i < frustum.cornerArray.length; i++)
    {
        var vector = frustum.cornerArray[i];
        if (this.containsVector3(vector) == ajax.xna.framework.ContainmentType.Disjoint)
            return ajax.xna.framework.ContainmentType.Intersects;
    }

    return ajax.xna.framework.ContainmentType.Contains;
}

//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.prototype.containsBoundingSphere = function(sphere)
{///<param name="sphere" type="ajax.xna.framework.BoundingSphere"/>
    var Vector3 = ajax.math.Vector3;
    var vector = Vector3.clamp(sphere.center, this.min, this.max);
    var num2 = Vector3.distanceSquared(sphere.center, vector);
    var radius = sphere.radius;
    if (num2 > (radius * radius))
        return ajax.xna.framework.ContainmentType.Disjoint;

    if (((((this.min.x + radius) <= sphere.center.x) && (sphere.center.x <= (this.max.x - radius))) && (((this.max.x - this.min.x) > radius) && ((this.min.y + radius) <= sphere.center.y))) && (((sphere.center.y <= (this.max.y - radius)) && ((this.max.y - this.min.y) > radius)) && ((((this.min.z + radius) <= sphere.center.z) && (sphere.center.z <= (this.max.z - radius))) && ((this.max.x - this.min.x) > radius))))
        return ajax.xna.framework.ContainmentType.Contains;

    return ajax.xna.framework.ContainmentType.Intersects;

}

// Statics
//-----------------------------------------------------------------------------
ajax.xna.framework.BoundingBox.cast = function(obj)
{///<returns type="ajax.xna.framework.BoundingBox"/>
    return obj;
}
